package gitee

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/go-redis/redis"
)

type UserInfo struct {
	ID        int    `json:"id"`         // 用户id
	Login     string `json:"login"`      // 用户名/邮箱/手机号
	Name      string `json:"name"`       // 名字
	AvatarUrl string `json:"avatar_url"` // 头像
}

func NewUserInfo() *UserInfo {
	return &UserInfo{}
}

// id login name avatar_url
func GetUserInfo(accessToken string) (*UserInfo, error) {
	client := http.Client{Timeout: time.Second * 10}
	url := "https://gitee.com/api/v5/user?access_token=" + accessToken
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)

	if err != nil {
		return nil, err
	}

	userInfo := NewUserInfo()
	err = json.Unmarshal(data, userInfo)

	if err != nil {
		return nil, err
	}

	return userInfo, nil
}

func (u *UserInfo) SaveUser() error {
	// gitee数据服务器返回信息中的ID
	userId := strconv.Itoa(u.ID)
	exists, err := rdb.HExists("userinfo:user-id", userId).Result()
	if err != nil {
		return err
	}

	// 如果用户已经存在，什么也不做？？
	if exists {
		return nil
	}

	// id: int64
	// 这里的id用来构建redis数据库中的键,如: userinfo:1
	// 区别于gitee数据服务器返回信息中的ID
	id, err := rdb.Incr("userinfo:next-id").Result()
	if err != nil {
		return err
	}

	key := fmt.Sprintf("userinfo:%d", id)

	pipe := rdb.Pipeline()
	pipe.HSet(key, "user_id", u.ID)
	pipe.HSet(key, "login", u.Login)
	pipe.HSet(key, "name", u.Name)
	pipe.HSet(key, "avatar_url", u.AvatarUrl)
	// 保存gitee传过来的唯一用户id,用来判断redis中是否已经保存过该用户信息
	pipe.HSet("userinfo:user-id", userId, fmt.Sprintf("%v", id))

	_, err = pipe.Exec()
	if err != nil {
		return err
	}

	return nil
}

func GetUserByUserId(userId string) (*UserInfo, error) {

	id, err := rdb.HGet("userinfo:user-id", userId).Result()

	if err == redis.Nil {
		return &UserInfo{}, err
	}

	if err != nil {
		return nil, err
	}

	userInfoMap, err := rdb.HGetAll("userinfo:" + id).Result()
	if err != nil {
		return nil, err
	}

	intId, err := strconv.Atoi(userInfoMap["user_id"])
	if err != nil {
		return nil, err
	}

	userInfo := UserInfo{
		ID:        intId,
		Login:     userInfoMap["login"],
		Name:      userInfoMap["name"],
		AvatarUrl: userInfoMap["avatar_url"],
	}

	return &userInfo, nil
}
